package server.core;

import server.*;
import server.deploy.FilterDef;
import server.deploy.FilterMap;
import server.util.RequestUtil;

import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import java.util.HashMap;




public class StandardContext extends ContainerBase implements Context {
    //后面删除
    public HashMap<String, FilterConfig> getFilterConfigs() {
        return filterConfigs;
    }

    //不完整
    //实现LifeCycle接口---------------------------------------------------------------------------
    @Override
    public synchronized void start() throws LifecycleException {
        if (started)
            throw new LifecycleException("Container {" + logName() + "} has already been started");
        if (debug >= 1)
            log("Starting");
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
        setAvailable(false);
        setConfigured(false);
        if (getLoader() == null)
            setLoader(new SimpleLoader());
        boolean ok = true;
        if (ok) {
            addDefaultMapper(mapperClass);
            started = true;
            if (loader != null && loader instanceof Lifecycle)
                ((Lifecycle) loader).start();
            if (logger != null && logger instanceof Lifecycle)
                ((Lifecycle) logger).start();
            for (Mapper mapper : findMappers()) {
                if (mapper instanceof Lifecycle)
                    ((Lifecycle) mapper).start();
            }
            for (Container container : findChildren()) {
                if (container instanceof Lifecycle)
                    ((Lifecycle) container).start();
            }
            if (pipeline instanceof Lifecycle)
                ((Lifecycle) pipeline).start();
            //触发启动事件,这时会有相应的监听器完成配置工作
            lifecycle.fireLifecycleEvent(START_EVENT, null);
        }
        //监听器配置失败
        if (!getConfigured())
            ok = false;
        if (ok) {
            if (debug >= 1)
                log("Starting completed");
            setAvailable(true);
        } else {
            log("Context startup failed due to previous errors");
            try {
                stop();
            } catch (Throwable t) {
                log("Exception during cleanup after start failed");
            }
            setAvailable(false);
        }
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    }

    @Override
    public void stop() throws LifecycleException {
        if (!started)
            throw new LifecycleException("Container {" + logName() + "} has not been started");
        if (debug >= 1)
            log("Stopping");
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
        setAvailable(false);
        filterStop();
        if (debug >= 1)
            log("Processing standard container shutdown");
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;
        if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).stop();
        }
        for (Container container : findChildren()) {
            if (container instanceof Lifecycle)
                ((Lifecycle) container).stop();
        }
        for (Mapper mapper : findMappers()) {
            if (mapper instanceof Lifecycle)
                ((Lifecycle) mapper).stop();
        }
        if ((logger != null) && (logger instanceof Lifecycle)) {
            ((Lifecycle) logger).stop();
        }
        if ((loader != null) && (loader instanceof Lifecycle)) {
            ((Lifecycle) loader).stop();
        }
        context = null;
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

        if (debug >= 1)
            log("Stopping complete");

    }

    public StandardContext() {
        pipeline.setBasic(new StandardContextValve());
    }
    //属性----------------------------------------------------------------------------
    //应用是否可用
    private boolean available = false;
    //是否配置成功
    private boolean configured = false;
    //应用信息
    private static final String info = "server.core.StandardContext/1.0";
    //匹配路径与servlet名之间的映射
    private HashMap<String, String> servletMappings = new HashMap<>();
    private HashMap<String, FilterConfig> filterConfigs = new HashMap<>();
    //存放过滤器名与拦截路径及拦截Servlet名之间的映射关系
    private FilterMap[] filterMaps = new FilterMap[0];
    //存放过滤器定义信息(以过滤器名为键)
    private HashMap<String, FilterDef> filterDefs = new HashMap<>();
    //默认的映射器全类名
    private String mapperClass = "server.core.StandardContextMapper";
    private ApplicationContext context = null;


    public FilterConfig findFilterConfig(String name) {
        synchronized (filterConfigs) {
            return filterConfigs.get(name);
        }
    }


    //校正匹配模式,除*.xxx格式外的路径必须以/开头
    private String adjustURLPattern(String pattern) {
        if (pattern == null || pattern.startsWith("/") || pattern.startsWith("*."))
            return pattern;
        log("WARNING: URL pattern {" + pattern + "} must start with a '/'");
        return "/" + pattern;
    }

    //验证匹配路径是否符合规则,符合返回true,否则返回false
    private boolean validateURLPattern(String pattern) {
        if (pattern == null)
            return false;
        if (pattern.startsWith("*.")) {
            //后缀中不能有/
            if (pattern.indexOf('/') < 0)
                return true;
            return false;
        }
        //除后缀匹配外,匹配路径都必须以/开头
        if (pattern.startsWith("/"))
            return true;
        return false;
    }

    //停止过滤器
    public void filterStop() {
        if (debug >= 1)
            log("Stopping filters");

        synchronized (filterConfigs) {
            for (FilterConfig filterConfig : filterConfigs.values()) {
                if (debug >= 1)
                    log(" Stopping filter '" + filterConfig.getFilterName() + "'");
                ApplicationFilterConfig afc = (ApplicationFilterConfig)filterConfig;
                afc.release();
            }
            filterConfigs.clear();
        }
    }
    //getter---------------------------------------------------------------------------

    //setter---------------------------------------------------------------------------

    //实现Container接口---------------------------------------------------------------------------
    @Override
    public String getInfo() {
        return info;
    }

    @Override
    public void addChild(Container child) {
        if (!(child instanceof Wrapper))
            throw new IllegalArgumentException("Child of a Context must be a Wrapper");
        super.addChild(child);
    }

    //实现Context接口---------------------------------------------------------------------------
    //后边写-----------
    @Override
    public ServletContext getServletContext() {
        return null;
    }




    //写好的-----------

    @Override
    public void removeFilterMap(FilterMap filterMap) {
        int index = -1;
        synchronized (filterMaps) {
            for (int i = 0; i < filterMaps.length; i++) {
                if (filterMaps[i] == filterMap) {
                    index = i;
                    break;
                }
            }
            if (index == -1)
                return;
            FilterMap[] newArr = new FilterMap[filterMaps.length - 1];
            int n = 0;
            for (int i = 0; i < filterMaps.length; i++) {
                if(i != index)
                    newArr[n++] = filterMaps[i];
            }
            filterMaps = newArr;
        }
    }

    @Override
    public void addFilterMap(FilterMap filterMap) {
        String filterName = filterMap.getFilterName();
        String servletName = filterMap.getServletName();
        String urlPattern = filterMap.getUrlPattern();
        if (findFilterDef(filterName) == null)
            throw new IllegalArgumentException("过滤器{" + filterName + "}未定义");
        if (servletName == null && urlPattern == null)
            throw new IllegalArgumentException("过滤器映射必须指定<url-pattern> 或 <servlet-name>");
        if (urlPattern != null && !validateURLPattern(urlPattern))
            throw new IllegalArgumentException("无效的匹配路径{" + urlPattern + "}");
        synchronized (filterMaps) {
            FilterMap[] newArr = new FilterMap[filterMaps.length + 1];
            System.arraycopy(filterMaps, 0, newArr, 0, filterMaps.length);
            newArr[filterMaps.length] = filterMap;
            filterMaps = newArr;
        }
    }
    @Override
    public FilterMap[] findFilterMaps() {
        return filterMaps;
    }


    @Override
    public void addFilterDef(FilterDef filterDef) {
        synchronized (filterDefs) {
            filterDefs.put(filterDef.getFilterName(), filterDef);
        }
    }

    @Override
    public FilterDef findFilterDef(String filterName) {
        synchronized (filterDefs) {
            return filterDefs.get(filterName);
        }
    }

    @Override
    public FilterDef[] findFilterDefs() {
        synchronized (filterDefs) {
            FilterDef[] defs = new FilterDef[filterDefs.size()];
            return filterDefs.values().toArray(defs);
        }
    }

    @Override
    public void removeFilterDef(FilterDef filterDef) {
        synchronized (filterDefs) {
            filterDefs.remove(filterDef.getFilterName());
        }
    }

    @Override
    public boolean getAvailable() {
        return available;
    }

    @Override
    public void setAvailable(boolean available) {
        this.available = available;
    }

    @Override
    public boolean getConfigured() {
        return configured;
    }

    @Override
    public void setConfigured(boolean configured) {
        this.configured = configured;
    }


    //根据匹配路径返回Wrapper名称
    @Override
    public String findServletMapping(String pattern) {
        synchronized (servletMappings) {
            return servletMappings.get(pattern);
        }
    }

    //返回所有匹配路径
    @Override
    public String[] findServletMappings() {
        synchronized (servletMappings) {
            String[] paths = new String[servletMappings.size()];
            return servletMappings.keySet().toArray(paths);
        }
    }

    //添加匹配路径与servlet名之间的关系
    @Override
    public void addServletMapping(String pattern, String name) {
        //如果添加的映射中容器名不存在与context中,抛出异常
        if (findChild(name) == null)
            throw new IllegalArgumentException("Context容器中不存在名称为{" + name + "}的wrapper");
        //校正部分匹配路径格式
        pattern = adjustURLPattern(RequestUtil.URLDecode(pattern));
        //验证匹配路径是否正常
        if (!validateURLPattern(pattern))
            throw new IllegalArgumentException("Invalid <url-pattern> {" + pattern + "} in servlet mapping");
        //添加
        synchronized (servletMappings) {
            servletMappings.put(pattern, name);
        }
    }


}
